<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------

namespace Home\Model;
use Think\Model;
use Think\Upload;

	/**
	 * 文件模型
	 * 负责文件的下载和上传
	 */

class FileModel extends Model {
	/**
	 * 文件模型自动完成
	 * @var array
	 */
	protected $_auto = array( array('create_time', NOW_TIME, self::MODEL_INSERT), );

	/**
	 * 文件模型字段映射
	 * @var array
	 */
	protected $_map = array('type' => 'mime', );

	/**
	 * 文件上传
	 * @param  array  $files   要上传的文件列表（通常是$_FILES数组）
	 * @param  array  $setting 文件上传配置
	 * @param  string $driver  上传驱动名称
	 * @param  array  $config  上传驱动配置
	 * @return array           文件上传成功后的信息
	 */
	public function upload($files, $setting, $driver = 'Local', $config = null) {
		/* 上传文件 */
		$setting['callback'] = array($this, 'isFile');
		$setting['removeTrash'] = array($this, 'removeTrash');
		$setting['savePath'] = strtolower(CONTROLLER_NAME) . "/";
		$setting['exts'] = array_filter(explode(",", get_system_config('upload_file_ext')), 'upload_filter');
		if(empty($setting['exts'])){
			$setting['exts']=C('UPLOAD_FILE_EXT');
		}
		$Upload = new Upload($setting, $driver, $config);		
		$info = $Upload -> upload($files);
		
		/* 设置文件保存位置 */
		$this -> _auto[] = array('location', 'ftp' === strtolower($driver) ? 1 : 0, self::MODEL_INSERT);
		if ($info) {//文件上传成功，记录文件信息
			foreach ($info as $key => &$value) {
				/* 已经存在文件记录 */
				if (isset($value['id']) && is_numeric($value['id'])) {
					$value['path'] = __ROOT__ . substr($setting['rootPath'], 1) . $value['savepath'] . $value['savename'];
					//在模板里的url路径
					continue;
				}
				//这里和上面加ROOT是为了兼容二级目录上传图片在kindeditor里回显正确
				$value['path'] = __ROOT__ . substr($setting['rootPath'], 1) . $value['savepath'] . $value['savename'];
				//在模板里的url路径
				/* 记录文件信息 */
				if ($this -> create($value) && ($id = $this -> add())) {
					$value['id'] = $id;
				} else {
					//TODO: 文件上传成功，但是记录文件信息失败，需记录日志
					unset($info[$key]);
				}
			}
			return $info;
			//文件上传成功
		} else {
			$this -> error = $Upload -> getError();
			return false;
		}
	}

	/**
	 * 下载指定文件
	 * @param  number  $root 文件存储根目录
	 * @param  integer $id   文件ID
	 * @param  string   $args     回调函数参数
	 * @return boolean       false-下载失败，否则输出下载文件
	 */
	public function download($root, $id, $callback = null, $args = null) {
		/* 获取下载文件信息 */
		$file = $this -> find($id);
		if (!$file) {
			$this -> error = '不存在该文件！';
			return false;
		}

		/* 下载文件 */
		switch ($file['location']) {
			case 0 :
				//下载本地文件
				$file['rootpath'] = $root;
				return $this -> downLocalFile($file, $callback, $args);
			case 1 :
				//下载FTP文件
				$file['rootpath'] = $root;
				return $this -> downFtpFile($file, $callback, $args);
				break;
			default :
				$this -> error = '不支持的文件存储类型！';
				return false;
		}
	}

	/**
	 * 检测当前上传的文件是否已经存在
	 * @param  array   $file 文件上传数组
	 * @return boolean       文件信息， false - 不存在该文件
	 */
	public function isFile($file) {
		if (empty($file['md5'])) {
			throw new \Exception('缺少参数:md5');
		}
		/* 查找文件 */
		$map = array('md5' => $file['md5'], 'sha1' => $file['sha1'], );
		// return $this->field(true)->where($map)->find();
		/* return false允许上传重复文件，以防止不同账号上传相同文件后一者删除另一者找不到*/
		return false;
	}

	/**
	 * 下载本地文件
	 * @param  array    $file     文件信息数组
	 * @param  callable $callback 下载回调函数，一般用于增加下载次数
	 * @param  string   $args     回调函数参数
	 * @return boolean            下载失败返回false
	 */
	private function downLocalFile($file, $callback = null, $args = null) {
		if (is_file($file['rootpath'] . $file['savepath'] . $file['savename'])) {
			/* 调用回调函数新增下载数 */
			is_callable($callback) && call_user_func($callback, $args);

			/* 执行下载 */ //TODO: 大文件断点续传
			header("Content-Description: File Transfer");
			header('Content-type: ' . $file['type']);
			header('Content-Length:' . $file['size']);
			$ua=$_SERVER['HTTP_USER_AGENT'];
			if (preg_match('/MSIE/',$ua) || preg_match("/Trident\/7.0/", $ua)) {
				header('Content-Disposition: attachment; filename="' . rawurlencode($file['name']) . '"');
			} else {
				header('Content-Disposition: attachment; filename="' . $file['name'] . '"');
			}
			readfile($file['rootpath'] . $file['savepath'] . $file['savename']);
			exit ;
		} else {
			$this -> error = '文件已被删除！';
			return false;
		}
	}

	/**
	 * 下载ftp文件
	 * @param  array    $file     文件信息数组
	 * @param  callable $callback 下载回调函数，一般用于增加下载次数
	 * @param  string   $args     回调函数参数
	 * @return boolean            下载失败返回false
	 */
	private function downFtpFile($file, $callback = null, $args = null) {
		/* 调用回调函数新增下载数 */
		is_callable($callback) && call_user_func($callback, $args);

		$host = C('DOWNLOAD_HOST.host');
		$root = explode('/', $file['rootpath']);
		$file['savepath'] = $root[3] . '/' . $file['savepath'];

		$data = array($file['savepath'], $file['savename'], $file['name'], $file['mime']);
		$data = json_encode($data);
		$key = think_encrypt($data, C('DATA_AUTH_KEY'), 600);

		header("Location:http://{$host}/onethink.php?key={$key}");
	}

	/**
	 * 清除数据库存在但本地不存在的数据
	 * @param $data
	 */
	public function removeTrash($data) {
		$this -> where(array('id' => $data['id'], )) -> delete();
	}

}
